"""
超声波MCP服务器实现
获取超声波传感器数据
"""

from typing import Dict, Any, Optional
from mcp.server.fastmcp import FastMCP
from sensors.ultrasonic_sensor import Measurement
import RPi.GPIO as GPIO


class UltrasonicServer(FastMCP):
    """超声波传感器服务器类"""

    def __init__(self, trig_pin: int = 12, echo_pin: int = 16):
        """初始化超声波传感器服务器

        Args:
            trig_pin: 触发信号引脚号
            echo_pin: 回响信号引脚号
        """
        super().__init__("ultrasonic_server")

        # 初始化超声波传感器
        self.sensor = Measurement(
            trig_pin=trig_pin,
            echo_pin=echo_pin,
            temperature=20,  # 默认温度20℃
            unit="metric",  # 默认使用公制单位
            round_to=1,  # 默认保留1位小数
            gpio_mode=GPIO.BCM,  # 默认使用BCM引脚编号
        )

        # 注册工具
        self._register_tools()

    def _register_tools(self):
        """注册所有超声波传感器工具"""

        @self.tool()
        async def get_distance(
            unit: str = "metric", sample_size: int = 11, sample_wait: float = 0.1
        ) -> Dict[str, Any]:
            """获取距离测量值

            Args:
                unit: 单位制('metric'或'imperial')
                sample_size: 采样数量
                sample_wait: 采样间隔时间(秒)

            Returns:
                Dict[str, Any]: 距离测量结果
            """
            try:
                # 获取原始距离值
                raw_distance = self.sensor.raw_distance(sample_size, sample_wait)

                # 根据单位制转换距离
                if unit == "metric":
                    distance = self.sensor.distance_metric(raw_distance)
                    unit_str = "cm"
                elif unit == "imperial":
                    distance = self.sensor.distance_imperial(raw_distance)
                    unit_str = "inches"
                else:
                    return {
                        "status": "error",
                        "message": "Invalid unit. Must be 'metric' or 'imperial'",
                    }

                return {
                    "status": "success",
                    "distance": distance,
                    "unit": unit_str,
                    "raw_distance": raw_distance,
                    "sample_size": sample_size,
                    "sample_wait": sample_wait,
                }
            except Exception as e:
                return {"status": "error", "message": str(e)}

        @self.tool()
        async def get_depth(
            hole_depth: float,
            unit: str = "metric",
            sample_size: int = 11,
            sample_wait: float = 0.1,
        ) -> Dict[str, Any]:
            """获取深度测量值

            Args:
                hole_depth: 传感器到洞底的距离
                unit: 单位制('metric'或'imperial')
                sample_size: 采样数量
                sample_wait: 采样间隔时间(秒)

            Returns:
                Dict[str, Any]: 深度测量结果
            """
            try:
                # 获取原始距离值
                raw_distance = self.sensor.raw_distance(sample_size, sample_wait)

                # 根据单位制转换深度
                if unit == "metric":
                    depth = self.sensor.depth_metric(raw_distance, hole_depth)
                    unit_str = "cm"
                elif unit == "imperial":
                    depth = self.sensor.depth_imperial(raw_distance, hole_depth)
                    unit_str = "inches"
                else:
                    return {
                        "status": "error",
                        "message": "Invalid unit. Must be 'metric' or 'imperial'",
                    }

                return {
                    "status": "success",
                    "depth": depth,
                    "unit": unit_str,
                    "hole_depth": hole_depth,
                    "raw_distance": raw_distance,
                    "sample_size": sample_size,
                    "sample_wait": sample_wait,
                }
            except Exception as e:
                return {"status": "error", "message": str(e)}

        @self.tool()
        async def set_temperature(
            temperature: float, unit: str = "metric"
        ) -> Dict[str, Any]:
            """设置环境温度

            Args:
                temperature: 环境温度值
                unit: 温度单位('metric'或'imperial')

            Returns:
                Dict[str, Any]: 执行结果
            """
            try:
                if unit not in ["metric", "imperial"]:
                    return {
                        "status": "error",
                        "message": "Invalid unit. Must be 'metric' or 'imperial'",
                    }

                self.sensor.temperature = temperature
                self.sensor.unit = unit

                return {
                    "status": "success",
                    "message": f"Set temperature to {temperature} {'°C' if unit == 'metric' else '°F'}",
                }
            except Exception as e:
                return {"status": "error", "message": str(e)}

        @self.tool()
        async def set_round_to(round_to: int) -> Dict[str, Any]:
            """设置结果保留小数位数

            Args:
                round_to: 保留小数位数

            Returns:
                Dict[str, Any]: 执行结果
            """
            try:
                self.sensor.round_to = round_to
                return {"status": "success", "message": f"Set round_to to {round_to}"}
            except Exception as e:
                return {"status": "error", "message": str(e)}

        @self.tool()
        async def get_sensor_info() -> Dict[str, Any]:
            """获取传感器配置信息

            Returns:
                Dict[str, Any]: 传感器配置信息
            """
            try:
                return {
                    "status": "success",
                    "data": {
                        "trig_pin": self.sensor.trig_pin,
                        "echo_pin": self.sensor.echo_pin,
                        "temperature": self.sensor.temperature,
                        "unit": self.sensor.unit,
                        "round_to": self.sensor.round_to,
                        "gpio_mode": (
                            "BCM" if self.sensor.gpio_mode == GPIO.BCM else "BOARD"
                        ),
                    },
                }
            except Exception as e:
                return {"status": "error", "message": str(e)}
